﻿using System;
using System.Collections.Generic;
using JWFW.Encrypt;
using JWFW.SFL;

namespace JWFW.Model.Register
{
    /// <summary>
    /// 注册模块－客户端基类
    /// </summary>
    public class BaseRegisterClient
    {
        /// <summary>
        /// 注册模块－客户端基类
        /// </summary>
        public BaseRegisterClient()
        {
            g_b64_2.CodeTable = @"STUVWXYZbacdefghi$klABCDEFGHIJKLMNOPQRmnopqrstu!wxyz0123456789+/";
            g_b64_2.Pad = "j";
            s_timer.Elapsed += new System.Timers.ElapsedEventHandler(g_timer_Elapsed);
        }



        /// <summary>
        /// 用于记录运行时防调试的时间
        /// </summary>
        protected DateTime g_runTime = DateTime.MinValue;

        /// <summary>
        /// 用于保存数据的字典
        /// </summary>
        protected Dictionary<string, string> g_hash = new Dictionary<string, string>();
        /// <summary>
        /// Base64加密类1
        /// </summary>
        protected Base64 g_b64 = new Base64();
        /// <summary>
        /// Base64加密类2
        /// </summary>
        protected Base64 g_b64_2 = new Base64();
        /// <summary>
        /// 用于防止调试的时钟
        /// </summary>
        protected System.Timers.Timer s_timer = new System.Timers.Timer();
        /// <summary>
        /// 防调时钟事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void g_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            ThrowException();
        }

        /// <summary>
        /// 用于保存数据的字典
        /// </summary>
        public Dictionary<string, string> Hash
        {
            get { return g_hash; }
        }

        #region 获取机器码

        /// <summary>
        /// 获取机器码：
        /// 流程：
        /// 1.获取硬盘序列号并补足到12位，同时存储在字典中备用
        /// 2.获取MAC并补足到12位，同时存储在字典中备用
        /// 3.硬盘序列号从前，MAC从后逐个字符叠加，并映射到A-Z之间
        /// 字典中备用的硬盘序列号以及MAC用于其他地方进行验证
        /// </summary>
        /// <returns>客户电脑的机器码</returns>
        public string GetMC()
        {
            try
            {
                SetTimer(true);
                string hdId = FillString(EnvironmentOP.GetHDInfo(0), 12);
                string mac = EnvironmentOP.GetMacAddress().Replace(":", "");
                mac = FillString(mac, 12);
                AddDictioanry("HD", hdId);
                AddDictioanry("MAC", mac);
                return g_b64.Encode(CreateMC(hdId, mac));
            }
            finally
            {
                SetTimer(false);
            }
        }
        /// <summary>
        /// 补足字符串长度
        /// </summary>
        /// <param name="origin">待补足长度的原始字符串</param>
        /// <param name="length">需要补足到的长度</param>
        /// <returns>补足后的字符串</returns>
        protected string FillString(string origin, int length)
        {
            SetTimer(true);
            string table = "DA12B4C35EF6";
            int delta = length - origin.Length;
            if (delta < 0)
            {
                return origin.Substring(0, length);
            }
            for (int i = 0; i < delta; i++)
            {
                SetTimer(true);
                int tmp = CommonOP.GetStringSum(origin, 0, origin.Length);
                tmp = tmp * 7 % table.Length;
                origin = origin + table[tmp].ToString();
            }
            return origin;
        }
        /// <summary>
        /// 创建机器码
        /// </summary>
        /// <param name="hdId">硬盘序列号</param>
        /// <param name="mac">网卡地址</param>
        /// <returns>交叉运算后的标识客户电脑的机器码</returns>
        protected string CreateMC(string hdId, string mac)
        {
            SetTimer(true);
            string res = "";
            for (int i = 0, j = hdId.Length - 1; i < hdId.Length; i++, j--)
            {
                int tmp = char.ConvertToUtf32(hdId, i) + char.ConvertToUtf32(mac, j);
                tmp = tmp % 26 + 65;
                res = res + char.ConvertFromUtf32(tmp);
            }
            return res;
        }
        /// <summary>
        /// 获得单机注册的机器码
        /// </summary>
        /// <param name="toolCode">工具的代码</param>
        /// <returns>用于单机注册的机器码</returns>
        public string GetPCMC(string toolCode)
        {
            string res = "";
            string mc = g_b64.Decode(this.GetMC());
            for (int i = 0; i < mc.Length; i++)
            {
                res += mc[i] + (toolCode.Length > i ? toolCode[i].ToString() : "");
            }
            return g_b64.Encode(res);
        }

        #endregion

        /// <summary>
        /// 组成提交到服务器的信息字符串
        /// </summary>
        /// <param name="userName">帐户名</param>
        /// <param name="productCode">软件产品代号</param>
        /// <param name="specialInfo">软件需要的额外信息，如网页游戏外挂需要知道额外的服务器url区分多个同名帐户</param>
        /// <param name="registerCode">客户拿到的注册码</param>
        /// <param name="version">客户试用的软件产品的版本</param>
        /// <returns>提交到服务器的客户端信息</returns>
        public string GetClientInfo(string userName, string productCode, string specialInfo, string registerCode, string version)
        {
            try
            {
                this.SetTimer(true);
                this.AddDictioanry("originUser", userName);
                this.AddDictioanry("originRc", registerCode);
                string res = CommonOP.Spliter + userName
                    + CommonOP.Spliter + productCode
                    + CommonOP.Spliter + specialInfo
                    + CommonOP.Spliter + this.GetMC()
                    + CommonOP.Spliter + registerCode
                    + CommonOP.Spliter + version;
                return g_b64.Encode(res);
            }
            finally
            {
                this.SetTimer(false);
            }
        }

        protected void Test()
        {
            Console.WriteLine(GetPCMC("QLJYJGHTHFYUIOHDFDG"));//QnFRaFdqQ1VOT1pUWVZL
        }

        /// <summary>
        /// 将需要储存的内容添加到字典
        /// </summary>
        /// <param name="key">内容的键</param>
        /// <param name="val">内容的值</param>
        protected void AddDictioanry(string key, string val)
        {
            SetTimer(true);
            if (g_hash.ContainsKey(key))
            {
                g_hash[key] = val;
            }
            else
            {
                g_hash.Add(key, val);
            }
        }

        /// <summary>
        /// 设置防止调试的时间，并检查上次设置的结果
        /// </summary>
        /// <param name="check">检查与否</param>
        protected void SetTime(bool check)
        {
            if (g_runTime == DateTime.MinValue)
            {
                if (check)
                {
                    g_runTime = DateTime.Now;
                }
                return;
            }
            else if (!check)
            {
                g_runTime = DateTime.MinValue;
            }
            else if (((TimeSpan)(DateTime.Now - g_runTime)).TotalMilliseconds <= 1000)
            {
                g_runTime = DateTime.Now;
            }
            else
            {
                ThrowException();
            }
        }
        /// <summary>
        /// 设置防止调试的时钟
        /// </summary>
        /// <param name="enable">启用时钟与否</param>
        protected void SetTimer(bool enable)
        {
            s_timer.Interval = 1000;
            s_timer.Enabled = enable;
            SetTime(enable);
        }
        /// <summary>
        /// 抛出异常
        /// </summary>
        public void ThrowException()
        {
            try
            {
                SetTimer(false);
                SetTimer(true);
                Random r = new Random((int)DateTime.Now.Ticks);
                int t = r.Next(20);
                SetTimer(true);
                if (t == 1)
                {
                    SetTimer(true);
                    int a = t / (t - 1);
                }
                else if (t == 2)
                {
                    SetTimer(true);
                    throw new NullReferenceException();
                }
                else if (t == 3)
                {
                    SetTimer(true);
                    int[] a = new int[3];
                    int b = a[4];
                }
            }
            finally
            {
                SetTimer(false);
            }
        }
        /// <summary>
        /// 获取字典中的值，当获取失败时返回空串
        /// </summary>
        /// <param name="key">要获取值的键</param>
        /// <returns>获取的值，当获取失败时返回空串</returns>
        public string GetDictionary(string key)
        {
            try
            {
                this.SetTimer(true);
                if (g_hash.ContainsKey(key))
                {
                    return g_hash[key];
                }
                return "";
            }
            finally
            {
                this.SetTimer(false);
            }
        }
    }
}
